package math

import (
	"go_gvm_mini/instructions/base"
	"go_gvm_mini/rtda"
	"reflect"
	"strings"
)

type SHIFT_LEFT[T interface{}] struct {
	base.NoOperandsInstruction
}

func (self *SHIFT_LEFT[T]) Execute(jFrame *rtda.JFrame) {
	stack := jFrame.OperandStack()
	e := reflect.TypeOf(self).Elem().String()
	etype := strings.ReplaceAll(strings.Split(e, "[")[1], "]", "")
	switch etype {
	case "int64":
		v2 := stack.PopLong()
		v1 := stack.PopLong()
		stack.PushLong(v1 << v2)
		break
	case "int32":
		v2 := stack.PopInt()
		v1 := stack.PopInt()
		stack.PushInt(v1 << v2)
		break
	}
}

type SHIFT_RIGHT[T interface{}] struct {
	base.NoOperandsInstruction
}

func (self *SHIFT_RIGHT[T]) Execute(jFrame *rtda.JFrame) {
	stack := jFrame.OperandStack()
	e := reflect.TypeOf(self).Elem().String()
	etype := strings.ReplaceAll(strings.Split(e, "[")[1], "]", "")
	switch etype {
	case "int64":
		v2 := stack.PopLong()
		v1 := stack.PopLong()
		stack.PushLong(v1 >> v2)
		break
	case "int32":
		v2 := stack.PopInt()
		v1 := stack.PopInt()
		stack.PushInt(v1 >> v2)
		break
	}
}

type ISHIFT_RIHGT struct {
	SHIFT_RIGHT[int32]
}

type ISHIFT_LEFT struct {
	SHIFT_LEFT[int32]
}

type LSHIFT_RIHGT struct {
	SHIFT_RIGHT[int64]
}

type LSHIFT_LEFT struct {
	SHIFT_LEFT[int64]
}
type LUSHIFT_RIGHT struct {
	base.NoOperandsInstruction
}

func (self *LUSHIFT_RIGHT) Execute(jFrame *rtda.JFrame) {
	stack := jFrame.OperandStack()
	v2 := stack.PopInt()
	v1 := stack.PopLong()
	stack.PushLong(v1 >> v2)
}

// Logical shift right int
type IUSHIFT_RIGHT struct{ base.NoOperandsInstruction }

func (sh *IUSHIFT_RIGHT) Execute(jFrame *rtda.JFrame) {
	stack := jFrame.OperandStack()
	v2 := stack.PopInt()
	v1 := stack.PopInt()
	s := uint32(v2) & 0x1f
	result := int32(uint32(v1) >> s)
	stack.PushInt(result)
}
